<template>
  <div class="h-full design-wrapper">
    <div class="flex items-center justify-between pr-20 design-header">
      <div class="flex items-center pl-20 left">
        <img src="https://res.songzhaopian.cn/rouzao-custom-platform/icon.png" alt="" />
        <div class="title">6cm透明亚克力打卡棒挂件D字扣款</div>
      </div>
      <div class="btn right">
        <el-button size="large">取消</el-button>
        <el-button size="large" type="primary">保存</el-button>
      </div>
    </div>
    <div class="design-main">
      <div class="design-canvas">
        <div id="coreContainer" ref="canvasContainer">
          <canvas ref="myCanvas" :width="canvasWidth" :height="canvasHeight"></canvas>
        </div>
        <div v-if="showUpload" class="upload-wrap w-[630px] h-[630px]">
          <div class="flex items-center justify-center upload-square">
            <el-upload class="upload-demo" :auto-upload="false" :on-change="handleUploadChange"
              :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" drag multiple>
              <el-icon class="el-icon--upload"><upload-filled /></el-icon>
              <div class="el-upload__text">
                Drop file here or <em>click to upload</em>
              </div>
            </el-upload>
          </div>
        </div>
      </div>
      <div class="design-edit"></div>
    </div>
  </div>
</template>

<script setup>
import { UploadFilled } from '@element-plus/icons-vue'
import { onMounted, onBeforeUnmount, ref, computed } from 'vue'
import Konva from 'konva'

const cv = window.cv

// 使用ref创建对DOM元素的引用
const canvasContainer = ref(null)
const myCanvas = ref(null)

let showUpload = ref(true)
let currentFile = ref(null)
// 创建响应式属性用于存储Canvas的宽度和高度
let canvasWidth = ref(0)
let canvasHeight = ref(0)

// 定义一个方法来调整Canvas尺寸并重绘内容
const resizeAndRedraw = () => {
  if (canvasContainer.value && myCanvas.value) {
    clearStage()
    canvasWidth.value = canvasContainer.value.clientWidth
    canvasHeight.value = canvasContainer.value.clientHeight
    initStage()
    redrawCanvasContent()
  }
}
// canvas实例
let state = ref(null)
let layer = ref(null)
// 图片实例
let _image = ref(null)
const initStage = () => {
  if (!layer.value) {
    state.value = new Konva.Stage({
      container: 'coreContainer',
      width: canvasWidth.value,
      height: canvasWidth.value,
    })

    layer.value = new Konva.Layer()
    state.value.add(layer.value)
  }
}
// 清除画布
const clearStage = () => {
  layer.value && layer.value.clear()
  state.value && state.value.clear()
  layer.value = null
  state.value = null
}
// 用于重绘Canvas内容的函数
const redrawCanvasContent = () => {
  if (currentFile.value) {
    drawImageOnCanvas(currentFile.value)
  }
}
const handleUploadChange = (uploadFile) => {
  currentFile.value = uploadFile
  drawImageOnCanvas(uploadFile)
}
const handleUploadSuccess = (response, file, fileList) => {
  console.log(response, response.data.url)
}
const handleBeforeUpload = (file) => {
  console.log(file)
}
const drawImageOnCanvas = (uploadFile) => {
  if (uploadFile) {
    const reader = new FileReader()
    reader.onload = (e) => {
      const img = new Image()
      img.onload = () => {
        resizeBase64Image(img.src).then(newImage => {
          const newImg = new Image()
          newImg.src = newImage
          newImg.onload = () => {
            drawBorderImage(newImg)
          }
        })
        showUpload.value = false
      }
      img.src = e.target.result // 将读取的文件内容设置为img的src
    }
    reader.readAsDataURL(uploadFile.raw) // 读取文件为DataURL
  } else {
    ElMessage.error('请选择有效的图片文件')
  }
}
const resizeBase64Image = (base64Image, maxHeight = 710) => {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.src = base64Image

    img.onload = function () {

      const canvas = document.createElement('canvas')
      let newHeight = maxHeight
      let newWidth = maxHeight


      if (img.height <= newHeight) {
        // 如果图片高度不大于指定最大高度，则不缩放
        newWidth = img.width;
        newHeight = img.height;
      }

      canvas.width = newWidth;
      canvas.height = newHeight;

      const ctx = canvas.getContext('2d')
      ctx.drawImage(img, 0, 0, newWidth, newHeight)

      // 将canvas内容重新转换为Base64编码
      const resizedBase64Image = canvas.toDataURL('image/png');

      resolve(resizedBase64Image);
    }
    img.onerror = function (error) {
      reject(new Error('Error loading image: ' + error));
    };
  })
}
const drawBorderImage = (img) => {
  let canvasWidth = myCanvas.value.width
  let canvasHeight = myCanvas.value.height
  var maxWidth = 735
  var maxHeight = 739
  let imgWidth = img.width
  let imgHeight = img.height
  let startX = (canvasWidth - imgWidth) / 2
  let startY = (canvasHeight - imgHeight) / 2
  console.log(imgWidth, imgHeight)
  Konva.Image.fromURL(img.src, function (image) {
    layer.value.add(image)
    _image.value = image
    image.setAttrs({
      x: startX,
      y: startY,
      borderSize: 10,
      borderColor: '#fff',
      lineSize: 2,
      lineColor: 'red',
    })
    image.filters([Border,BorderLine]);
    image.cache()
  })
}

function removeTransparency (canvas) {
  var ctx = canvas.getContext('2d')

  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
  var nPixels = imageData.data.length
  for (var i = 3; i < nPixels; i += 4) {
    if (imageData.data[i] > 0) {
      imageData.data[i] = 255
    }
  }
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  ctx.putImageData(imageData, 0, 0)
  return canvas
}
var canvas = document.createElement('canvas')
var tempCanvas = document.createElement('canvas')
// 绘制图片轮廓
const Border = (imageData) => {
  var nPixels = imageData.data.length

  var size = _image.value.getAttr('borderSize') || 0

  // - first set correct dimensions for canvases
  canvas.width = imageData.width
  canvas.height = imageData.height

  tempCanvas.width = imageData.width
  tempCanvas.height = imageData.height

  // - the draw original shape into temp canvas
  tempCanvas.getContext('2d').putImageData(imageData, 0, 0)

  // - then we need to remove alpha chanel, because it will affect shadow (transparent shapes has smaller shadow)
  removeTransparency(tempCanvas)

  var ctx = canvas.getContext('2d')
  var color = _image.value.getAttr('borderColor') || 'black'

  // 3. we will use shadow as border
  // so we just need apply shadow on the original image
  ctx.save()
  ctx.shadowColor = color
  ctx.shadowBlur = size

  ctx.drawImage(tempCanvas, 0, 0)
  ctx.restore()
  // - Then we will dive in into image data of [original image + shadow]
  // and remove transparency from shadow
  var tempImageData = ctx.getImageData(0, 0, canvas.width, canvas.height)

  var SMOOTH_MIN_THRESHOLD = 3
  var SMOOTH_MAX_THRESHOLD = 10

  let val, hasValue

  var offset = 10

  for (var i = 3; i < nPixels; i += 4) {
    // skip opaque pixels
    if (imageData.data[i] === 255) {
      continue
    }

    val = tempImageData.data[i]
    hasValue = val !== 0
    if (!hasValue) {
      continue
    }
    if (val > SMOOTH_MAX_THRESHOLD) {
      val = 255
    } else if (val < SMOOTH_MIN_THRESHOLD) {
      val = 0
    } else {
      val =
        ((val - SMOOTH_MIN_THRESHOLD) /
          (SMOOTH_MAX_THRESHOLD - SMOOTH_MIN_THRESHOLD)) *
        255
    }
    tempImageData.data[i] = val
  }

  // draw resulted image (original + shadow without opacity) into canvas
  ctx.putImageData(tempImageData, 0, 0)

  // then fill whole image with color (after that shadow is colored)
  ctx.save()
  ctx.globalCompositeOperation = 'source-in'
  ctx.fillStyle = color
  ctx.fillRect(0, 0, canvas.width, canvas.height)
  ctx.restore()

  // then we need to copy colored shadow into original imageData
  var newImageData = ctx.getImageData(0, 0, canvas.width, canvas.height)

  var indexesToProcess = []
  for (var i = 3; i < nPixels; i += 4) {
    var hasTransparentOnTop =
      imageData.data[i - imageData.width * 4 * offset] === 0
    var hasTransparentOnTopRight =
      imageData.data[i - (imageData.width * 4 + 4) * offset] === 0
    var hasTransparentOnTopLeft =
      imageData.data[i - (imageData.width * 4 - 4) * offset] === 0
    var hasTransparentOnRight = imageData.data[i + 4 * offset] === 0
    var hasTransparentOnLeft = imageData.data[i - 4 * offset] === 0
    var hasTransparentOnBottom =
      imageData.data[i + imageData.width * 4 * offset] === 0
    var hasTransparentOnBottomRight =
      imageData.data[i + (imageData.width * 4 + 4) * offset] === 0
    var hasTransparentOnBottomLeft =
      imageData.data[i + (imageData.width * 4 - 4) * offset] === 0
    var hasTransparentAround =
      hasTransparentOnTop ||
      hasTransparentOnRight ||
      hasTransparentOnLeft ||
      hasTransparentOnBottom ||
      hasTransparentOnTopRight ||
      hasTransparentOnTopLeft ||
      hasTransparentOnBottomRight ||
      hasTransparentOnBottomLeft

    // if pixel presented in original image - skip it
    // because we need to change only shadow area
    if (
      imageData.data[i] === 255 ||
      (imageData.data[i] && !hasTransparentAround)
    ) {
      continue
    }
    if (!newImageData.data[i]) {
      // skip transparent pixels
      continue
    }
    indexesToProcess.push(i)
  }

  for (var index = 0; index < indexesToProcess.length; index += 1) {
    var i = indexesToProcess[index]

    var alpha = imageData.data[i] / 255

    if (alpha > 0 && alpha < 1) {
      var aa = 1 + 1
    }
    imageData.data[i] = newImageData.data[i]
    imageData.data[i - 1] =
      newImageData.data[i - 1] * (1 - alpha) + imageData.data[i - 1] * alpha
    imageData.data[i - 2] =
      newImageData.data[i - 2] * (1 - alpha) + imageData.data[i - 2] * alpha
    imageData.data[i - 3] =
      newImageData.data[i - 3] * (1 - alpha) + imageData.data[i - 3] * alpha

    if (newImageData.data[i] < 255 && alpha > 0) {
      var bb = 1 + 1
    }
  }
}
// 绘制轮廓描边
const BorderLine = (imageData) => {
  var nPixels = imageData.data.length

  var size = _image.value.getAttr('lineSize') || 0

  // - first set correct dimensions for canvases
  canvas.width = imageData.width
  canvas.height = imageData.height

  tempCanvas.width = imageData.width
  tempCanvas.height = imageData.height

  // - the draw original shape into temp canvas
  tempCanvas.getContext('2d').putImageData(imageData, 0, 0)

  // - then we need to remove alpha chanel, because it will affect shadow (transparent shapes has smaller shadow)
  removeTransparency(tempCanvas)

  var ctx = canvas.getContext('2d')
  var color = _image.value.getAttr('lineColor') || 'black'

  // 3. we will use shadow as border
  // so we just need apply shadow on the original image
  ctx.save()
  ctx.shadowColor = color
  ctx.shadowBlur = size

  ctx.drawImage(tempCanvas, 0, 0)
  ctx.restore()
  // - Then we will dive in into image data of [original image + shadow]
  // and remove transparency from shadow
  var tempImageData = ctx.getImageData(0, 0, canvas.width, canvas.height)

  var SMOOTH_MIN_THRESHOLD = 3
  var SMOOTH_MAX_THRESHOLD = 10

  let val, hasValue

  var offset = 10

  for (var i = 3; i < nPixels; i += 4) {
    // skip opaque pixels
    if (imageData.data[i] === 255) {
      continue
    }

    val = tempImageData.data[i]
    hasValue = val !== 0
    if (!hasValue) {
      continue
    }
    if (val > SMOOTH_MAX_THRESHOLD) {
      val = 255
    } else if (val < SMOOTH_MIN_THRESHOLD) {
      val = 0
    } else {
      val =
        ((val - SMOOTH_MIN_THRESHOLD) /
          (SMOOTH_MAX_THRESHOLD - SMOOTH_MIN_THRESHOLD)) *
        255
    }
    tempImageData.data[i] = val
  }

  // draw resulted image (original + shadow without opacity) into canvas
  ctx.putImageData(tempImageData, 0, 0)

  // then fill whole image with color (after that shadow is colored)
  ctx.save()
  ctx.globalCompositeOperation = 'source-in'
  ctx.fillStyle = color
  ctx.fillRect(0, 0, canvas.width, canvas.height)
  ctx.restore()

  // then we need to copy colored shadow into original imageData
  var newImageData = ctx.getImageData(0, 0, canvas.width, canvas.height)

  var indexesToProcess = []
  for (var i = 3; i < nPixels; i += 4) {
    var hasTransparentOnTop =
      imageData.data[i - imageData.width * 4 * offset] === 0
    var hasTransparentOnTopRight =
      imageData.data[i - (imageData.width * 4 + 4) * offset] === 0
    var hasTransparentOnTopLeft =
      imageData.data[i - (imageData.width * 4 - 4) * offset] === 0
    var hasTransparentOnRight = imageData.data[i + 4 * offset] === 0
    var hasTransparentOnLeft = imageData.data[i - 4 * offset] === 0
    var hasTransparentOnBottom =
      imageData.data[i + imageData.width * 4 * offset] === 0
    var hasTransparentOnBottomRight =
      imageData.data[i + (imageData.width * 4 + 4) * offset] === 0
    var hasTransparentOnBottomLeft =
      imageData.data[i + (imageData.width * 4 - 4) * offset] === 0
    var hasTransparentAround =
      hasTransparentOnTop ||
      hasTransparentOnRight ||
      hasTransparentOnLeft ||
      hasTransparentOnBottom ||
      hasTransparentOnTopRight ||
      hasTransparentOnTopLeft ||
      hasTransparentOnBottomRight ||
      hasTransparentOnBottomLeft

    // if pixel presented in original image - skip it
    // because we need to change only shadow area
    if (
      imageData.data[i] === 255 ||
      (imageData.data[i] && !hasTransparentAround)
    ) {
      continue
    }
    if (!newImageData.data[i]) {
      // skip transparent pixels
      continue
    }
    indexesToProcess.push(i)
  }

  for (var index = 0; index < indexesToProcess.length; index += 1) {
    var i = indexesToProcess[index]

    var alpha = imageData.data[i] / 255

    if (alpha > 0 && alpha < 1) {
      var aa = 1 + 1
    }
    imageData.data[i] = newImageData.data[i]
    imageData.data[i - 1] =
      newImageData.data[i - 1] * (1 - alpha) + imageData.data[i - 1] * alpha
    imageData.data[i - 2] =
      newImageData.data[i - 2] * (1 - alpha) + imageData.data[i - 2] * alpha
    imageData.data[i - 3] =
      newImageData.data[i - 3] * (1 - alpha) + imageData.data[i - 3] * alpha

    if (newImageData.data[i] < 255 && alpha > 0) {
      var bb = 1 + 1
    }
  }
}
// 使用onMounted生命周期钩子来初始化Canvas大小并监听窗口resize事件
onMounted(() => {
  resizeAndRedraw() // 初始化时调整尺寸
  window.addEventListener('resize', resizeAndRedraw)
})

// 使用onBeforeUnmount清理监听器，避免内存泄漏
onBeforeUnmount(() => {
  window.removeEventListener('resize', resizeAndRedraw)
})
</script>

<style lang="scss" scoped>
canvas {
  display: block;
  background-color: #f0f0f0;
}

.design-wrapper {
  .design-header {
    width: 100%;
    padding-left: 20px;
    background-color: #fff;
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    box-shadow: inset 0 -1px #e6e8ec;
    position: relative;
    z-index: 4;

    .left {
      display: flex;
      align-items: center;
      height: 100%;

      img {
        width: auto;
        height: 50% !important;
      }

      .title {
        position: relative;
        font-size: 18px;
        line-height: 18px;
        font-weight: 500;
        padding: 10px 20px;
        color: #121212;
        margin-left: 20px;
        border-left: 1px solid #e6e8ec;
      }
    }
  }

  .design-main {
    display: flex;
    width: 100%;
    height: calc(100vh - 60px);

    .design-canvas {
      flex: auto;
      height: 100%;
      position: relative;
      display: flex;
      justify-content: center;
      align-items: center;

      #coreContainer {
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        width: 100%;
        height: 100%;
        max-height: 1000px;
      }

      .upload-wrap {
        z-index: 1;
        transform: scale(1.01);
        pointer-events: none;

        .upload-square {
          pointer-events: all;
          position: relative;
          width: 100%;
          height: 100%;
          background-color: #fff;
        }
      }
    }

    .design-edit {
      background: #fff;
      position: relative;
      z-index: 4;
      flex: none;
      width: 360px;
      height: 100%;
    }
  }
}
</style>
